#include <QUndoStack>

#include<gp_Pnt2d.hxx>
#include<gp_Pln.hxx>
#include<gp_Dir.hxx>
#include <GeomAPI.hxx>
#include<Geom2d_Curve.hxx>
#include<Geom_Curve.hxx>
#include<Geom_TrimmedCurve.hxx>
#include<Geom2d_TrimmedCurve.hxx>
#include<Geom2d_Line.hxx>
#include<Geom_Line.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include<TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>

#include "Surface.h"
#include "Ent.h"
#include "Qt3DPicker.h"
#include "CmdManager.h"
#include "Scene.h"
#include "SendPointHandlerBase.h"
#include "SelectHandler3D.h"
#include "CurveRevolutionHandler.h"
#include "OSGNodeMask.h"
#include "Ucs.h"
#include "LineStrip2D.h"
#include "LineStrip3D.h"
#include "Operation/OpAdd.h"
#include "Operation/OpDelete.h"
#include "OcctShapeProp.h"
#include "OcctMisc.h"
#include "EntFromEdge.h"

CurveRevolutionHandler::CurveRevolutionHandler()
{
}
CurveRevolutionHandler::~CurveRevolutionHandler()
{
}

void CurveRevolutionHandler::input(const QVariant & data, const QString & rawInput, CommandSource cs)
{
	auto scene = getScene();
	auto sph = getSendPointHandler();
	auto selector = qobject_cast<SelectHandler3D*>(getSelectHandler());
	if (data.type() == QVariant::Bool)
	{
		bool esc = !data.toBool();
		if (esc)
		{
			selector->clearSelection();
			clearInput();
			emit finished();
			return;
		}
	}

	if (status() == 0)
	{
		if (sph)
		{
			sph->setPointMask(CS_LBTNDOWN);
		}
		if (selector)
		{
			selector->clearSelection();
			selector->beginSelect(D2LineMask | D3LineMask, 1);
			prompt(1, tr("选择旋转轴: "));
		}
		else
		{
			emit finished();
		}
		return;
	}

	if (status() == 1)
	{
		if (selector && selector->done())
		{
			auto selections = selector->selectionSet();
			if (selections.empty())
			{
				emit finished();
				return;
			}
			m_axis = std::dynamic_pointer_cast<Ent>(*selections.begin());
			auto parent = m_axis->getParent();
			UCS* ucs = dynamic_cast<UCS*>(parent);
			if (ucs)
			{
				std::shared_ptr<LineStrip2D> line2d = std::dynamic_pointer_cast<LineStrip2D>(m_axis);
				assert(line2d);
				auto points = line2d->getPoints();
				if (points.size() != 2)
				{
					selector->clearSelection();
					prompt(2, tr("请选择单段线"));
					return;
				}
			}
			else
			{
				std::shared_ptr<LineStrip3D> line3d = std::dynamic_pointer_cast<LineStrip3D>(m_axis);
				assert(line3d);
				auto points = line3d->getPoints();
				if (points.size() != 2)
				{
					selector->clearSelection();
					prompt(2, tr("请选择线段"));
					return;
				}
			}
		}
		selector->clearSelection();
		selector->beginSelect(D2CurveMask | D3CurveMask, 1);
		prompt(2, tr("选择要旋转的曲线: "));
		return;
	}

	if (status() == 2)
	{
		if (selector && selector->done())
		{
			auto selections = selector->selectionSet();
			if (selections.empty())
			{
				emit finished();
				return;
			}
			m_curve = std::dynamic_pointer_cast<Ent>(*selections.begin());
			prompt(3, tr("请输入旋转角度:"));
		}
		return;
	}
	
	if (status() == 3)
	{
		if (data.type() == QVariant::Double && data.toDouble())
		{
			if ((data.toDouble() > 360.0) || (data.toDouble() <= 0.0))
			{
				prompt(3, tr("旋转角度超出范围，请重新输入旋转角度"));
				return;
			}
			m_angle = data.toDouble() / 180 * M_PI;
			generateSurface();
		}
		selector->clearSelection();
		prompt(4, tr("是否需要反向旋转[是(Y)/否(N)]<N>:"));
		return;
	}

	if (status() == 4)
	{
		if (data.type() == QVariant::String)
		{
			auto command = data.value<QString>();
			if (command.compare("Y", Qt::CaseInsensitive) == 0)
			{
				auto undoStack = scene->undoStack();
				undoStack->undo();
				m_angle = -m_angle;
				generateSurface();
			}
			selector->beginSelect(D2CurveMask | D3CurveMask, 1);
			prompt(2, tr("选择要旋转的曲线: "));
		}
		return;
	}
}

TopoDS_Face makeRevolutionFace(const Handle(Geom_Line)& axis, const TopoDS_Edge& curve, double angle)
{
	TopoDS_Face face;
	BRepPrimAPI_MakeRevol maker(curve, axis->Position(), angle, false);
	if (maker.IsDone())
	{
		TopoDS_Shape shape = maker.Shape();
		face = TopoDS::Face(shape);
	}
	return face;
}

Handle(Geom_Line) convertAxis(const std::shared_ptr<Ent>& axis)
{
	auto line2d = dynamic_cast<LineStrip2D*>(axis.get());
	if (line2d)
	{
		auto curve2ds = line2d->getCurve2d();
		Handle(Geom2d_Curve) first = curve2ds[0];
		auto ucs = dynamic_cast<UCS*>(line2d->getParent());
		Handle(Geom_Curve) curve = curves2dTo3d(first, ucs->getPln());
		return Handle(Geom_Line)::DownCast(basisCurve(curve));
	}
	auto line3d = dynamic_cast<LineStrip3D*>(axis.get());
	auto curve3ds = line3d->getCurve3d();
	Handle(Geom_Curve) first = curve3ds[0];
	return Handle(Geom_Line)::DownCast(basisCurve(first));
}

void CurveRevolutionHandler::generateSurface()
{
	Handle(Geom_Line) axis = convertAxis(m_axis);
	auto edges = makeEdges(m_curve);
	std::set<std::shared_ptr<INode>> result;
	auto scene = getScene();
	for (int i = 0; i < edges.size(); i++)
	{
		BRepPrimAPI_MakeRevol maker(edges[i], axis->Position(), m_angle, false);
		if (maker.IsDone())
		{
			TopoDS_Shape shape = maker.Shape();
			TopoDS_Face face = TopoDS::Face(shape);
			auto surface = std::make_shared<Surface>(scene);
			surface->setShape(face);
			result.insert(surface);
		}
	}
	auto undoStack = scene->undoStack();
	undoStack->push(new OpAdd(result));
}
